#include "XmlClient.hh"
#include "../Gui/Bolygo.hh"
#include "../Gui/ConnectWindow.hh"
#include "../Gui/MainWindow.hh"
#include "../Gui/GameWindow.hh"
#include "../Gui/Flotta.hh"
#include "../Exception.hh"
#include "GetGameList.hh"
#include "NewGame.hh"
#include "NextTurn.hh"
#include "ChatFromClient.hh"
#include "JoinGame.hh"
#include "FleetMove.hh"
#include "FleetAttackFleet.hh"
#include "FleetAttackPlanet.hh"
#include "FleetColonizePlanet.hh"
#include "PlanetAddTask.hh"
#include "../Geom/Vector.hh"

using namespace Network;
using namespace Geom;
using namespace Gui;

XmlClient* XmlClient::client;

XmlClient& XmlClient::instance() {
	if (!client)
		client = new XmlClient();

	return *client;
}

XmlClient::XmlClient():
    state(START),
    socket(),
    key(),
    certificate(),
    ca(),
    connectWindow(new ConnectWindow()),
    mainWindow()
{
    // ConnectWindow <--> XmlClient
    connect(
      this,             SIGNAL(state_changed(ClientState)),
      connectWindow,    SLOT(client_state_changed(ClientState))
    );
    connect(
      connectWindow,    SIGNAL(connect_to_server(QString,u2)),
      this,             SLOT(connect_to_server(QString, u2))
    );

    // ConnectWindow <--> XmlSocket
    connect(
      &socket,          SIGNAL(stateChanged(QAbstractSocket::SocketState)),
      connectWindow,    SLOT(socket_state_changed(QAbstractSocket::SocketState))
    );
    connect(
      &socket,          SIGNAL(error(QAbstractSocket::SocketError)),
      connectWindow,    SLOT(socket_error(QAbstractSocket::SocketError))
    );

    // XmlClient <--> XmlSocket
    connect(
      &socket,  SIGNAL(stateChanged(QAbstractSocket::SocketState)),
      this,     SLOT(socket_state_changed(QAbstractSocket::SocketState))
    );
    connect(
      &socket,  SIGNAL(message_recieved()),
      this,     SLOT(process_message())
    );
}

void XmlClient::ssl_config(QString key_path, QString cert_path, QString ca_path) {
	key = key_path;
	certificate = cert_path;
	ca = ca_path;
}

void XmlClient::start() {
    connectWindow->show();
}

void XmlClient::show_main_window() {
    connectWindow->close();
    mainWindow = new MainWindow();
    connect(
      this,         SIGNAL(game_list_rcvd(Network::GameList::GameListInfo)),
      mainWindow,   SLOT(show_game_list(Network::GameList::GameListInfo))
    );
    connect(
      mainWindow,   SIGNAL(refresh_game_list()),
      this,         SLOT(send_get_game_list())
    );
    connect(
      mainWindow,    SIGNAL(send_new_game_message(QString, u2, u2)),
      this,			 SLOT(send_new_game(QString, u2, u2))
    );
    connect(
    	mainWindow,	 SIGNAL(refresh_game_list()),
		this,		 SLOT(refresh_game_list())
	);
	connect(
	   mainWindow,	SIGNAL(join(QString)),
	   this,	    SLOT(send_join(QString))
	);
	connect(
		mainWindow,		SIGNAL(send_chat_msg_to_server(QString)),
		this,			SLOT(send_chat_msg_to_server(QString))
	);
    mainWindow->show();
}

void XmlClient::show_game_window() {
    gameWindow = new GameWindow();
    connect(
      gameWindow, SIGNAL(korvaltas()),
      this,       SLOT(send_new_turn())
	);
    connect(
      gameWindow, SIGNAL(send_chat_msg_to_server(QString)),
      this,       SLOT(send_chat_msg_to_server(QString))
    );
    connect(
      gameWindow, SIGNAL(attack_fleet(Gui::Flotta*, Gui::Flotta*)),
      this,       SLOT(send_attack_fleet(Gui::Flotta*, Gui::Flotta*))
    );
    connect(
      gameWindow, SIGNAL(attack_planet(Gui::Flotta*, u8, Gui::Bolygo*)),
      this,       SLOT(send_attack_planet(Gui::Flotta*, u8, Gui::Bolygo*))
    );
    connect(
      gameWindow, SIGNAL(colonize_planet(Gui::Flotta*, u8, Gui::Bolygo*)),
      this,       SLOT(send_colonize_planet(Gui::Flotta*, u8, Gui::Bolygo*))
    );
    connect(
      gameWindow, SIGNAL(build(Gui::Csillag*, Gui::Bolygo*, QString, u8)),
      this,       SLOT(send_add_task(Gui::Csillag*, Gui::Bolygo*, QString, u8))
    );
    mainWindow->hide();
    gameWindow->show();
}

void XmlClient::process_game_list(GameList::GameListInfo const& gameListInfo) {
    emit game_list_rcvd(gameListInfo);
}

ClientState XmlClient::get_state() const {
    return state;
}

void XmlClient::set_state(ClientState value) {
    state = value;
    emit state_changed(state);
}

XmlSocket& XmlClient::get_socket() {
    return socket;
}

void
XmlClient::connect_to_server(QString host, u2 port) {
    socket.addCaCertificates(ca);
	socket.setLocalCertificate(certificate);
	socket.setPrivateKey(key);
    socket.connectToHostEncrypted(host, port);
}

void XmlClient::socket_state_changed(QAbstractSocket::SocketState socketState) {
    if (socketState == QAbstractSocket::ConnectedState) {
    	username = socket.localCertificate().subjectInfo(
    			QSslCertificate::CommonName);
        set_state(AUTHENTICATED);
        show_main_window();
        GetGameList getGameList;
        getGameList.send_to(socket);
        set_state(INIT_GET_GAME_LIST_SENT);
    }
}

void XmlClient::process_message() {
    try {
        spXmlMessage message = XmlMessage::construct(socket.read());
        message->process_on_client(*this);
    } catch (ProtocolError& ex) {
        qDebug("%s", ex.what());
        socket.disconnectFromHost();
    }
}

void XmlClient::send_new_game(QString name, u2 min, u2 max) {
	NewGame newgame(name, min, max);
	newgame.send_to(get_socket());
	set_state(INIT_NEW_GAME_SENT);
}

void XmlClient::send_new_turn()
{
		NextTurn msg;
		msg.send_to(get_socket());
		set_state(NEXT_TURN_SENT);
}

void XmlClient::refresh_game_list()
{
    GetGameList getGameList;
    getGameList.send_to(socket);
    set_state(INIT_GET_GAME_LIST_SENT);
}

void XmlClient::message(QString param)
{
	QMessageBox::warning(NULL, "x", param);
}

void XmlClient::send_join(QString s)
{
	JoinGame msg(s);
	msg.send_to(get_socket());
	set_state(INIT_JOIN_SENT);
}

void XmlClient::clear() {
    gameWindow->clear();
}

void XmlClient::show_fleet(StateChanged::FleetInfo fi, QString s) {
	gameWindow->show_fleet(fi, s);
}

void XmlClient::show_star(StateChanged::StarInfo const& si) {
    gameWindow->show_star(si);
}

void XmlClient::move_selected_fleet(Vector<> pos) {
	StateChanged::FleetInfo fi = gameWindow->get_selected_fleet()->fi;
	qDebug("X %f;Y %f", pos.x, pos.y);
	FleetMove msg(fi.id, pos);
	msg.send_to(socket);
}

void XmlClient::chat_msg_received(QString sender, QString msg) {
	if (mainWindow->isVisible()) {
		mainWindow->chat_msg_received(sender, msg);
	} else if (gameWindow->isVisible()) {
		gameWindow->chat_msg_received(sender, msg);
	}
}

void XmlClient::send_chat_msg_to_server(QString message) {
	ChatFromClient chatmessage(message);
	chatmessage.send_to(socket);
}

QString XmlClient::get_name()
{
	//visszaadja a user nevet
	return socket.localCertificate().subjectInfo(QSslCertificate::CommonName);
}

void XmlClient::send_attack_fleet(Flotta* attacker, Flotta* target) {
    FleetAttackFleet msg(
      attacker->get_id(), target->get_player(), target->get_id()
    );
    msg.send_to(socket);
}

void XmlClient::send_attack_planet(
  Flotta* attacker, u8 starId, Bolygo* target
) {
    qDebug("slot! XmlClient::send_attack_planet");
    FleetAttackPlanet msg(
      attacker->get_id(), starId, target->get_id()
    );
    msg.send_to(socket);
}

void XmlClient::send_colonize_planet(
  Flotta* fleet, u8 starId, Bolygo* target
) {
    qDebug("slot! XmlClient::send_colonize_planet");
    FleetColonizePlanet msg(
      fleet->get_id(), starId, target->get_id()
    );
    msg.send_to(socket);
}

void XmlClient::send_add_task(
  Gui::Csillag* star, Gui::Bolygo* planet, QString what, u8 count
) {
    qDebug("slot! XmlClient::send_add_task");
    PlanetAddTask msg(star->get_id(), planet->get_id(), what, count);
    msg.send_to(socket);
}
